package com.nku.mason.masonframework.util;

import java.io.File;
import java.io.FileFilter;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * 类操作工具
 * @author Mason
 * @date 2017年3月10日
 */
public final class ClassUtil {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtil.class);
	
	private ClassUtil(){
		//私有构造器，防止外部实例化
	}
	
	/**
	 * 获取类加载器
	 * @return
	 */
	public static ClassLoader getClassLoader(){
		//返回当前线程的类加载器
		return Thread.currentThread().getContextClassLoader();
	}
	
	/**
	 * 加载类
	 * @param className
	 * @param isIntialized 为了提高加载性能，可将该参数设置为false
	 * @return
	 */
	public static Class<?> loadClass(String className, boolean isIntialized){
		Class<?> clazz;
		try {
			clazz = Class.forName(className, isIntialized, getClassLoader());
		} catch (ClassNotFoundException e) {
			LOGGER.debug("class loading failed", e);
			throw new RuntimeException(e);
		}
		return clazz;
	}
	
	/**
	 * 上面加载类的方法的重载,默认类不进行初始化
	 * @param className
	 * @return
	 */
	public static Class<?> loadClass(String className){
		Class<?> clazz;
		try {
			clazz = Class.forName(className, false, getClassLoader());
		} catch (ClassNotFoundException e) {
			LOGGER.debug("class loading failed", e);
			throw new RuntimeException(e);
		}
		return clazz;
	}

	/**
	 * 获取指定包名下的所有类
	 * @param packageName
	 * @return
	 */
	public static Set<Class<?>> getClassSet(String packageName){
		Set<Class<?>> classSet = new HashSet<Class<?>>();
		try {
			Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".", "/"));
			while (urls.hasMoreElements()) {
				URL url = (URL) urls.nextElement();
				if (url != null) {
					String protocol = url.getProtocol();
					if (protocol.equals("file")) {
						String packagePath = url.getPath().replaceAll("%20", "");//%20是URL编码中的空格
						addClass(classSet, packagePath, packageName);
					} else if (protocol.equals("jar")){
						/*
						 * A URL Connection to a Java ARchive (JAR) file or an entry in a JAR file. 
							The syntax of a JAR URL is: 
							 jar:<url>!/{entry}
						 */
						JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
						if (jarURLConnection != null) {
							JarFile jarFile = jarURLConnection.getJarFile();
							if (jarFile != null) {
								Enumeration<JarEntry> jarEntries = jarFile.entries();
								while (jarEntries.hasMoreElements()) {
									JarEntry jarEntry = (JarEntry) jarEntries.nextElement();
									String jarEntryName = jarEntry.getName();
									if (jarEntryName.endsWith(".class")) {
										String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
										doAddClass(classSet, className);
									}
								}
							}
						}
					}
				}
			}
		} catch (Exception e) {
			LOGGER.error("get class set failue" , e);
			throw new RuntimeException(e);
		}
		
		return classSet;
	}
	
	/**
	 * 根据当前给出的包路径和包名来列出该包下的所有类
	 * @param classSet 要返回的类集合
	 * @param packagePath 包路径
	 * @param packageName 包名
	 */
	private static void addClass(Set<Class<?>> classSet, String packagePath, String packageName){
		File[] files = new File(packagePath).listFiles(new FileFilter() {
			@Override
			public boolean accept(File file) {
				return (file.isFile() && file.getName().endsWith(".class") || file.isDirectory());
			}
		});
		
		for(File file : files){
			String fileName = file.getName();
			
			if (file.isFile()) {
				String className = fileName.substring(0,fileName.lastIndexOf("."));
				if (!StringUtil.isEmpty(packageName)) {
					className = packageName + "." + className;
				}
				doAddClass(classSet, className);
			} else {
				String subPackagePath = fileName;
				if (!StringUtil.isEmpty(packagePath)){
					subPackagePath = packagePath + "/" + subPackagePath;
				}
				String subPackageName = fileName;
				if (!StringUtil.isEmpty(packageName)) {
					subPackageName = packageName + "." + subPackageName;
				}
				addClass(classSet, subPackagePath, subPackageName);
			}
		}
	}
	
	//完成类加载
	private static void doAddClass(Set<Class<?>> classSet, String className){
		Class<?> cls = loadClass(className, false);
		classSet.add(cls);
	}
}































